<script setup lang="ts">
import { ElPopover, type ElTable, type ElTree } from 'element-plus'
import { cloneDeep } from 'lodash-es'
import { Md5 } from 'ts-md5'

import TableItem from '@/components/common-table/table-item.vue'
import type { ColumnsType } from '@/components/common-table/types'
import Preview from '@/components/material/preview.vue'
import cache from '@/utils/cache'

type PropsType = {
  size?: 'large' | 'default' | 'small' | ''
  pager: {
    loading: boolean
    lists: any[]
  }
  columns: ColumnsType[]
  optionsConfig?: {
    [key in ColumnsType['prop']]?: {
      label: string
      value: any
    }[] | undefined
  }
  selectable?: (row: any) => boolean
  isSelection?: boolean
  isRadio?: boolean
  radioData?: any
  fixed?: boolean | 'left' | 'right'
  actions?: {
    label: string
    width: string
    fixed: string
  }
  selectableConfig?: {
    field: string
  }
  showSet?: boolean
  showOverflowTooltip?: boolean
    rowKey?:string | ((row: any) => string)
}

const props = withDefaults(defineProps<PropsType>(), {
  size: 'default',
  pager: () => ({ loading: true, lists: [] }),
  columns: () => [],
  isSelection: false,
  selectable: () => true,
  isRadio: false,
  radioData: 0,
  fixed: false,
  actions: () => ({
    label: '操作',
    width: '',
    fixed: 'right'
  }),
  selectableConfig: () => ({
    field: 'id'
  }),
  showSet: true,
  showOverflowTooltip: true,
    rowKey: (row: any) => {
        return row.id?.toString()
    }
})

const emits = defineEmits<{
  (e: 'selectionChange', val: any[]): void
  (e: 'radioChange', val: any): void
  (e: 'switchChanged', val: any): void
  (e: 'edit', val: any): void
  (e: 'handleSortChange', val: any): void
}>()

const md5 = new Md5()

const treeRef = shallowRef<InstanceType<typeof ElTree>>()
const popoverRef = shallowRef<InstanceType<typeof ElPopover>>()
const elTableRef = shallowRef<InstanceType<typeof ElTable>>()

const previewUrl = ref('')
const showPreview = ref(false)
const header = ref<any[]>()
const type = ref('image')
const actionsWidth = ref(1)

const slotActions = useSlots()?.actions

const headerMd5 = `${location.pathname}_${
  md5.appendStr(JSON.stringify(props.columns)).end() as string
}`

// eslint-disable-next-line vue/no-dupe-keys
const selectionData = defineModel<any[]>('selectionData')
// eslint-disable-next-line vue/no-dupe-keys
const radioData = defineModel<any>('radioData', {
  get(val) {
    return val
  }
})

const getPropsFromColumns = (columns: ColumnsType[], property: keyof ColumnsType) => {
  const props: any[] = []

  columns.forEach((column) => {
    if (column[property]) {
      props.push(column[property])
    }

    if (column.columns) {
      const nestedProps = getPropsFromColumns(column.columns, property)
      props.push(...nestedProps)
    }
  })

  return props
}

onMounted(() => {
  header.value = cache.get(headerMd5)
  if (!header.value) {
    cache.set(headerMd5, getPropsFromColumns(props.columns, 'prop'))
  }
  header.value = cache.get(headerMd5)
})

const handleShow = () => {
  treeRef.value?.setCheckedKeys(header.value || [], true)
}

const handleSetHeader = async () => {
  cache.set(headerMd5, treeRef.value?.getCheckedKeys())
  await nextTick()
  header.value = cache.get(headerMd5)
  elTableRef.value?.doLayout()
  popoverRef.value?.hide()
}

const defaultActions = Object.assign(
  {
    label: '操作',
    width: '200',
    fixed: 'right'
  },
  props.actions
)

const renderHeader = async () => {
  const opts = elTableRef.value?.$el.getElementsByClassName('optionDiv')
  const widthArr: number[] = []
  // 取操作组的最大宽度
  Array.prototype.forEach.call(opts, function (item) {
    if (item.innerText) {
      widthArr.push(item.offsetWidth)
    }
  })
  if (widthArr.length > 0) {
    actionsWidth.value = Math.max.apply(null, widthArr) + 32
  }
  if (widthArr.length == 0) {
    actionsWidth.value = 1
  }
  await nextTick()
  elTableRef.value?.doLayout()
}

watch(
  () => props.pager.lists,
  async () => {
    await nextTick()
    await renderHeader()
    props.pager.lists?.map((item) => {
      if (selectionData.value?.includes(item[props.selectableConfig?.field]))
        elTableRef.value?.toggleRowSelection(item, true)
      if (props.radioData == item[props.selectableConfig?.field])
        elTableRef.value?.setCurrentRow(item)
    })
  },
  {
    deep: true,
    immediate: true
  }
)

const selectionChange = (res: any) => {
  let data = cloneDeep(selectionData.value)
  data = data?.filter((v) => {
    return props.pager.lists.findIndex((d: any) => d[props.selectableConfig?.field] == v) == -1
  })
  selectionData.value = Array.from(
    new Set(data?.concat(res.map((v: any) => v[props.selectableConfig?.field])))
  )
  emits('selectionChange', res)
}

const handleCurrentChange = (res: any) => {
  radioData.value = res?.[props.selectableConfig?.field]
  emits('radioChange', res)
}

const handleSortChange = (res: any) => {
  emits('handleSortChange', res)
}

// const rowKey = (row: any) => {
//   return row.id?.toString()
// }

const toggleRowSelection = (row: any) => {
  const data = elTableRef.value
    ?.getSelectionRows()
    ?.find((v: any) => v[props.selectableConfig?.field] == row)
  data && elTableRef.value?.toggleRowSelection(data)
}

const clearSelection = () => {
  elTableRef.value?.clearSelection()
}

defineExpose({
  toggleRowSelection,
  clearSelection
})
</script>

<template>
  <div v-loading="pager.loading">
    <div class="flex justify-between mb-[10px]">
      <div>
          <slot name="btns"></slot>
      </div>
      <div v-if="showSet">
          <el-popover
              title="设置表头"
              ref="popoverRef"
              :width="300"
              trigger="click"
              @show="handleShow"
          >
              <template #reference>
                  <el-button icon="Menu" circle />
              </template>
              <div>
                  <el-divider class="!my-[5px]" />
                  <div class="max-h-[30vh] overflow-y-auto">
                      <el-tree
                          ref="treeRef"
                          :data="[
                    {
                      label: '全部',
                      prop: 'all',
                      columns
                    }
                  ]"
                          draggable
                          show-checkbox
                          node-key="prop"
                          :default-expand-all="true"
                          :props="{
                    label: 'label',
                    children: 'columns'
                  }"
                      />
                  </div>
                  <el-divider class="!mt-[5px] !mb-[10px]" />
                  <div class="flex justify-between items-center">
                      <div></div>
                      <div>
                          <el-link :underline="false" type="danger" @click="popoverRef?.hide()"
                          >取消</el-link
                          >
                          <el-link
                              class="ml-[10px]"
                              :underline="false"
                              type="primary"
                              @click="handleSetHeader"
                          >确认</el-link
                          >
                      </div>
                  </div>
              </div>
          </el-popover>
      </div>
    </div>
    <div>
      <!--      @selection-change="(newSelection) => emits('selectionChange', newSelection)"-->
      <el-table
        border
        :size="size"
        ref="elTableRef"
        :data="pager.lists"
        :row-key="rowKey"
        :show-overflow-tooltip="showOverflowTooltip"
        :highlight-current-row="isRadio && !isSelection"
        @selection-change="selectionChange"
        @current-change="handleCurrentChange"
        @sort-change="handleSortChange"
      >
        <el-table-column
          v-if="isSelection && !isRadio"
          type="selection"
          :selectable="selectable"
          :reserve-selection="true"
          width="55"
        />
        <template v-for="(column, i) in columns" :key="i">
          <table-item
            :show-overflow-tooltip="showOverflowTooltip"
            :fixed="column.fixed"
            :column="column"
            :optionsConfig="optionsConfig"
            v-if="header?.includes(column.prop)"
            @switch-changed="(v:any) => emits('switchChanged', v)"
            @edit="(v:any)=>emits('edit',v)"
          />
        </template>
        <el-table-column
          :class-name="!!slotActions && actionsWidth != 1 ? '' : 'actionsWidth'"
          v-if="slotActions && actionsWidth"
          :label="defaultActions.label"
          :width="actionsWidth"
          :fixed="defaultActions.fixed"
        >
          <template #default="{ row }">
            <div class="optionDiv w-[max-content]"><slot name="actions" :row="row"></slot></div>
          </template>
        </el-table-column>
      </el-table>
      <preview v-model="showPreview" :url="previewUrl" :type="type" />
    </div>
  </div>
</template>

<style scoped lang="scss">
.actionsWidth {
  display: none;
}

:deep(.actionsWidth) {
  .cell {
    padding: 0;
  }
}
</style>
